﻿/*!
 * Copyright (c), 上海沃恩信息科技有限公司.
 * All rights reserved.
 * Licensed under BSD (https://www.pittypat.work/bsd.html).
 */

using System;

namespace Pittypat
{
    /// <summary>
    /// 对基础值提供扩展方法。
    /// </summary>
    public static class PrimitiveExtensions
    {
        #region ToBinary

        internal static @binary? ToBinary(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        return value as byte[];
                    }

                    if (value is string)
                    {
                        string s = value as string;
                        if (s == null)
                        {
                            return null;
                        }

                        if (s.Length == 0)
                        {
                            return @binary.Empty;
                        }

                        return (@binary)(string)value;
                    }

                    if (value is Guid)
                    {
                        return @binary.Parse("0x" + ((Guid)value).ToString("N"));
                    }

                    if (value is DateTime)
                    {
                        return BitConverter.GetBytes(((DateTime)value).Ticks);
                    }

                    if (value is DateTimeOffset)
                    {
                        return BitConverter.GetBytes(((DateTimeOffset)value).Ticks);
                    }

                    if (value is TimeSpan)
                    {
                        return BitConverter.GetBytes(((TimeSpan)value).Ticks);
                    }

                    if (value is bool)
                    {
                        return ((bool)value) ? BinaryHelper.True : BinaryHelper.Empty;
                    }

                    if (value is byte)
                    {
                        return new byte[] { (byte)value };
                    }

                    if (value is sbyte)
                    {
                        return new byte[] { (byte)(sbyte)value };
                    }

                    if (value is short)
                    {
                        return BitConverter.GetBytes(((short)value));
                    }

                    if (value is ushort)
                    {
                        return BitConverter.GetBytes(((ushort)value));
                    }

                    if (value is int)
                    {
                        return BitConverter.GetBytes(((int)value));
                    }

                    if (value is uint)
                    {
                        return BitConverter.GetBytes(((uint)value));
                    }

                    if (value is long)
                    {
                        return BitConverter.GetBytes(((long)value));
                    }

                    if (value is ulong)
                    {
                        return BitConverter.GetBytes(((ulong)value));
                    }

                    if (value is decimal)
                    {
                        int[] bits = Decimal.GetBits((decimal)value);
                        byte[] data = new byte[16];
                        Buffer.BlockCopy(BitConverter.GetBytes(bits[0]), 0, data, 0, 4);
                        Buffer.BlockCopy(BitConverter.GetBytes(bits[1]), 0, data, 4, 4);
                        Buffer.BlockCopy(BitConverter.GetBytes(bits[2]), 0, data, 8, 4);
                        Buffer.BlockCopy(BitConverter.GetBytes(bits[3]), 0, data, 12, 4);

                        return data;
                    }

                    if (value is float)
                    {
                        return BitConverter.GetBytes(((float)value));
                    }

                    if (value is double)
                    {
                        return BitConverter.GetBytes(((double)value));
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region ToBoolean

        internal static @bool? ToBoolean(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        return (value as byte[]).Length > 0;
                    }

                    if (value is string)
                    {
                        string s = value as string;
                        if (String.IsNullOrEmpty(s))
                        {
                            return null;
                        }

                        s = s.ToLower();
                        if (s == "true" || s == "t" || s == "1" || s == "yes" || s == "y" || s == "on" || s == "是")
                        {
                            return true;
                        }
                        else if (s == "false" || s == "f" || s == "0" || s == "no" || s == "n" || s == "off" || s == "否")
                        {
                            return false;
                        }

                        return null;
                    }

                    if (value is Guid)
                    {
                        return ((Guid)value) != Guid.Empty;
                    }

                    if (value is DateTime)
                    {
                        return ((DateTime)value).Ticks != 0;
                    }

                    if (value is DateTimeOffset)
                    {
                        return ((DateTimeOffset)value).Ticks != 0;
                    }

                    if (value is TimeSpan)
                    {
                        return ((TimeSpan)value).Ticks != 0;
                    }

                    if (value is bool)
                    {
                        return ((bool)value);
                    }

                    if (value is byte)
                    {
                        return (byte)value != 0;
                    }

                    if (value is sbyte)
                    {
                        return (sbyte)value != 0;
                    }

                    if (value is short)
                    {
                        return (short)value != 0;
                    }

                    if (value is ushort)
                    {
                        return (ushort)value != 0;
                    }

                    if (value is int)
                    {
                        return (int)value != 0;
                    }

                    if (value is uint)
                    {
                        return (uint)value != 0;
                    }

                    if (value is long)
                    {
                        return (long)value != 0;
                    }

                    if (value is ulong)
                    {
                        return (ulong)value != 0;
                    }

                    if (value is decimal)
                    {
                        return (decimal)value != 0m;
                    }

                    if (value is float)
                    {
                        return (float)value != 0f;
                    }

                    if (value is double)
                    {
                        return (double)value != 0d;
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region ToUuid

        internal static @uuid? ToUuid(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        var v = value as byte[];

                        if (v.Length > 16)
                        {
                            var tv = new byte[16];
                            Array.Copy(v, tv, 16);
                            v = tv;
                        }
                        else if (v.Length < 16)
                        {
                            v = BinaryHelper.PadRight(v, 16);
                        }
                        
                        return @uuid.Parse(((@binary)v).ToString("x"));
                    }

                    if (value is string)
                    {
                        return @uuid.Parse(value as string);
                    }

                    if (value is Guid)
                    {
                        return (Guid)value;
                    }

                    if (value is DateTime)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes(((DateTime)value).Ticks), 16));
                    }

                    if (value is DateTimeOffset)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes(((DateTimeOffset)value).Ticks), 16));
                    }

                    if (value is TimeSpan)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes(((TimeSpan)value).Ticks), 16));
                    }

                    if (value is bool)
                    {
                        return new Guid(BinaryHelper.PadRight((bool)value ? BinaryHelper.True : BinaryHelper.Empty, 16));
                    }

                    if (value is byte)
                    {
                        return new Guid(BinaryHelper.PadRight(new byte[] { (byte)value }, 16));
                    }

                    if (value is sbyte)
                    {
                        return new Guid(BinaryHelper.PadRight(new byte[] { (byte)(sbyte)value }, 16));
                    }

                    if (value is short)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes((short)value), 16));
                    }

                    if (value is ushort)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes((ushort)value), 16));
                    }

                    if (value is int)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes((int)value), 16));
                    }

                    if (value is uint)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes((uint)value), 16));
                    }

                    if (value is long)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes((long)value), 16));
                    }

                    if (value is ulong)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes((ulong)value), 16));
                    }

                    if (value is decimal)
                    {
                        var v = ToBinary(value);
                        if (v.HasValue)
                        {
                            return new Guid(BinaryHelper.PadRight(v.Value, 16));
                        }
                        return null;
                    }

                    if (value is float)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes((float)value), 16));
                    }

                    if (value is double)
                    {
                        return new Guid(BinaryHelper.PadRight(BitConverter.GetBytes((double)value), 16));
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region ToInt64

        internal static @int64? ToInt64(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        return BitConverter.ToInt64(BinaryHelper.PadRight(value as byte[], 8), 0);
                    }

                    if (value is string)
                    {
                        long v = 0;
                        if (long.TryParse(value as string, out v))
                        {
                            return v;
                        }
                        return null;
                    }

                    if (value is Guid)
                    {
                        return BitConverter.ToInt64(((Guid)value).ToByteArray(), 0);
                    }

                    if (value is DateTime)
                    {
                        return ((DateTime)value).Ticks;
                    }

                    if (value is DateTimeOffset)
                    {
                        return ((DateTimeOffset)value).Ticks;
                    }

                    if (value is TimeSpan)
                    {
                        return ((TimeSpan)value).Ticks;
                    }

                    if (value is bool)
                    {
                        return ((bool)value) ? 1L : 0L;
                    }

                    if (value is byte)
                    {
                        return (byte)value;
                    }

                    if (value is sbyte)
                    {
                        return (sbyte)value;
                    }

                    if (value is short)
                    {
                        return (short)value;
                    }

                    if (value is ushort)
                    {
                        return (ushort)value;
                    }

                    if (value is int)
                    {
                        return (int)value;
                    }

                    if (value is uint)
                    {
                        return (uint)value;
                    }

                    if (value is long)
                    {
                        return (long)value;
                    }

                    if (value is ulong)
                    {
                        return (long)(ulong)value;
                    }

                    if (value is decimal)
                    {
                        return (long)(decimal)value;
                    }

                    if (value is float)
                    {
                        return (long)(float)value;
                    }

                    if (value is double)
                    {
                        return (long)(double)value;
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion
        
        #region ToInt32

        internal static @int32? ToInt32(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        return BitConverter.ToInt32(BinaryHelper.PadRight(value as byte[], 4), 0);
                    }

                    if (value is string)
                    {
                        int v = 0;
                        if (int.TryParse(value as string, out v))
                        {
                            return v;
                        }
                        return null;
                    }

                    if (value is Guid)
                    {
                        return BitConverter.ToInt32(((Guid)value).ToByteArray(), 0);
                    }

                    if (value is DateTime)
                    {
                        return (int)((DateTime)value).Ticks;
                    }

                    if (value is DateTimeOffset)
                    {
                        return (int)((DateTimeOffset)value).Ticks;
                    }

                    if (value is TimeSpan)
                    {
                        return (int)((TimeSpan)value).Ticks;
                    }

                    if (value is bool)
                    {
                        return ((bool)value) ? 1 : 0;
                    }

                    if (value is byte)
                    {
                        return (byte)value;
                    }

                    if (value is sbyte)
                    {
                        return (sbyte)value;
                    }

                    if (value is short)
                    {
                        return (short)value;
                    }

                    if (value is ushort)
                    {
                        return (ushort)value;
                    }

                    if (value is int)
                    {
                        return (int)value;
                    }

                    if (value is uint)
                    {
                        return (int)(uint)value;
                    }

                    if (value is long)
                    {
                        return (int)(long)value;
                    }

                    if (value is ulong)
                    {
                        return (int)(ulong)value;
                    }

                    if (value is decimal)
                    {
                        return (int)(decimal)value;
                    }

                    if (value is float)
                    {
                        return (int)(float)value;
                    }

                    if (value is double)
                    {
                        return (int)(double)value;
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion
        
        #region ToInt16

        internal static @int16? ToInt16(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        return BitConverter.ToInt16(BinaryHelper.PadRight(value as byte[], 2), 0);
                    }

                    if (value is string)
                    {
                        short v = 0;
                        if (short.TryParse(value as string, out v))
                        {
                            return v;
                        }
                        return null;
                    }

                    if (value is Guid)
                    {
                        return BitConverter.ToInt16(((Guid)value).ToByteArray(), 0);
                    }

                    if (value is DateTime)
                    {
                        return (short)((DateTime)value).Ticks;
                    }

                    if (value is DateTimeOffset)
                    {
                        return (short)((DateTimeOffset)value).Ticks;
                    }

                    if (value is TimeSpan)
                    {
                        return (short)((TimeSpan)value).Ticks;
                    }

                    if (value is bool)
                    {
                        return (short)(((bool)value) ? 1 : 0);
                    }

                    if (value is byte)
                    {
                        return (byte)value;
                    }

                    if (value is sbyte)
                    {
                        return (sbyte)value;
                    }

                    if (value is short)
                    {
                        return (short)value;
                    }

                    if (value is ushort)
                    {
                        return (short)(ushort)value;
                    }

                    if (value is int)
                    {
                        return (short)(int)value;
                    }

                    if (value is uint)
                    {
                        return (short)(uint)value;
                    }

                    if (value is long)
                    {
                        return (short)(long)value;
                    }

                    if (value is ulong)
                    {
                        return (short)(ulong)value;
                    }

                    if (value is decimal)
                    {
                        return (short)(decimal)value;
                    }

                    if (value is float)
                    {
                        return (short)(float)value;
                    }

                    if (value is double)
                    {
                        return (short)(double)value;
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion
        
        #region ToInt8

        internal static @int8? ToInt8(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        return (value as byte[]).Length == 0 ? (@int8?)null : (@int8?)(sbyte)(value as byte[])[0];
                    }

                    if (value is string)
                    {
                        sbyte v = 0;
                        if (sbyte.TryParse(value as string, out v))
                        {
                            return v;
                        }
                        return null;
                    }

                    if (value is Guid)
                    {
                        return (sbyte)((Guid)value).ToByteArray()[0];
                    }

                    if (value is DateTime)
                    {
                        return (sbyte)((DateTime)value).Ticks;
                    }

                    if (value is DateTimeOffset)
                    {
                        return (sbyte)((DateTimeOffset)value).Ticks;
                    }

                    if (value is TimeSpan)
                    {
                        return (sbyte)((TimeSpan)value).Ticks;
                    }

                    if (value is bool)
                    {
                        return (sbyte)(((bool)value) ? 1 : 0);
                    }

                    if (value is byte)
                    {
                        return (sbyte)(byte)value;
                    }

                    if (value is sbyte)
                    {
                        return (sbyte)value;
                    }

                    if (value is short)
                    {
                        return (sbyte)(short)value;
                    }

                    if (value is ushort)
                    {
                        return (sbyte)(ushort)value;
                    }

                    if (value is int)
                    {
                        return (sbyte)(int)value;
                    }

                    if (value is uint)
                    {
                        return (sbyte)(uint)value;
                    }

                    if (value is long)
                    {
                        return (sbyte)(long)value;
                    }

                    if (value is ulong)
                    {
                        return (sbyte)(ulong)value;
                    }

                    if (value is decimal)
                    {
                        return (sbyte)(decimal)value;
                    }

                    if (value is float)
                    {
                        return (sbyte)(float)value;
                    }

                    if (value is double)
                    {
                        return (sbyte)(double)value;
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion
        
        #region ToDecimal

        internal static @decimal? ToDecimal(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        var bytes = BinaryHelper.PadRight(value as byte[], 16);
                        int[] bits = new int[4];
                        bits[0] = BitConverter.ToInt32(bytes, 0);
                        bits[1] = BitConverter.ToInt32(bytes, 4);
                        bits[2] = BitConverter.ToInt32(bytes, 8);
                        bits[3] = BitConverter.ToInt32(bytes, 12);

                        return new Decimal(bits);
                    }

                    if (value is string)
                    {
                        decimal v = 0;
                        if (decimal.TryParse(value as string, out v))
                        {
                            return v;
                        }
                        return null;
                    }

                    if (value is Guid)
                    {
                        return ToDecimal(((Guid)value).ToByteArray());
                    }

                    if (value is DateTime)
                    {
                        return (decimal)((DateTime)value).Ticks;
                    }

                    if (value is DateTimeOffset)
                    {
                        return (decimal)((DateTimeOffset)value).Ticks;
                    }

                    if (value is TimeSpan)
                    {
                        return (decimal)((TimeSpan)value).Ticks;
                    }

                    if (value is bool)
                    {
                        return (decimal)(((bool)value) ? 1 : 0);
                    }

                    if (value is byte)
                    {
                        return (byte)value;
                    }

                    if (value is sbyte)
                    {
                        return (decimal)(sbyte)value;
                    }

                    if (value is short)
                    {
                        return (decimal)(short)value;
                    }

                    if (value is ushort)
                    {
                        return (decimal)(ushort)value;
                    }

                    if (value is int)
                    {
                        return (decimal)(int)value;
                    }

                    if (value is uint)
                    {
                        return (decimal)(uint)value;
                    }

                    if (value is long)
                    {
                        return (decimal)(long)value;
                    }

                    if (value is ulong)
                    {
                        return (decimal)(ulong)value;
                    }

                    if (value is decimal)
                    {
                        return (decimal)value;
                    }

                    if (value is float)
                    {
                        return (decimal)(float)value;
                    }

                    if (value is double)
                    {
                        return (decimal)(double)value;
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region ToSingle

        internal static @float32? ToSingle(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        return BitConverter.ToSingle(BinaryHelper.PadRight(value as byte[], 4), 0);
                    }

                    if (value is string)
                    {
                        float v = 0;
                        if (float.TryParse(value as string, out v))
                        {
                            return v;
                        }
                        return null;
                    }

                    if (value is Guid)
                    {
                        return BitConverter.ToSingle(((Guid)value).ToByteArray(), 0);
                    }

                    if (value is DateTime)
                    {
                        return ((DateTime)value).Ticks;
                    }

                    if (value is DateTimeOffset)
                    {
                        return ((DateTimeOffset)value).Ticks;
                    }

                    if (value is TimeSpan)
                    {
                        return ((TimeSpan)value).Ticks;
                    }

                    if (value is bool)
                    {
                        return ((bool)value) ? 1 : 0;
                    }

                    if (value is byte)
                    {
                        return (byte)value;
                    }

                    if (value is sbyte)
                    {
                        return (sbyte)value;
                    }

                    if (value is short)
                    {
                        return (short)value;
                    }

                    if (value is ushort)
                    {
                        return (ushort)value;
                    }

                    if (value is int)
                    {
                        return (int)value;
                    }

                    if (value is uint)
                    {
                        return (uint)value;
                    }

                    if (value is long)
                    {
                        return (long)value;
                    }

                    if (value is ulong)
                    {
                        return (ulong)value;
                    }

                    if (value is decimal)
                    {
                        return (float)(decimal)value;
                    }

                    if (value is float)
                    {
                        return (float)value;
                    }

                    if (value is double)
                    {
                        return (float)(double)value;
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region ToDouble

        internal static @float64? ToDouble(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        return BitConverter.ToDouble(BinaryHelper.PadRight(value as byte[], 8), 0);
                    }

                    if (value is string)
                    {
                        double v = 0;
                        if (double.TryParse(value as string, out v))
                        {
                            return v;
                        }
                        return null;
                    }

                    if (value is Guid)
                    {
                        return BitConverter.ToDouble(((Guid)value).ToByteArray(), 0);
                    }

                    if (value is DateTime)
                    {
                        return ((DateTime)value).Ticks;
                    }

                    if (value is DateTimeOffset)
                    {
                        return ((DateTimeOffset)value).Ticks;
                    }

                    if (value is TimeSpan)
                    {
                        return ((TimeSpan)value).Ticks;
                    }

                    if (value is bool)
                    {
                        return ((bool)value) ? 1 : 0;
                    }

                    if (value is byte)
                    {
                        return (byte)value;
                    }

                    if (value is sbyte)
                    {
                        return (sbyte)value;
                    }

                    if (value is short)
                    {
                        return (short)value;
                    }

                    if (value is ushort)
                    {
                        return (ushort)value;
                    }

                    if (value is int)
                    {
                        return (int)value;
                    }

                    if (value is uint)
                    {
                        return (uint)value;
                    }

                    if (value is long)
                    {
                        return (long)value;
                    }

                    if (value is ulong)
                    {
                        return (ulong)value;
                    }

                    if (value is decimal)
                    {
                        return (double)(decimal)value;
                    }

                    if (value is float)
                    {
                        return (float)value;
                    }

                    if (value is double)
                    {
                        return (double)value;
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region ToDate

        internal static @date? ToDate(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        var v1 = ToInt32(value as byte[]);
                        if (v1.HasValue)
                        {
                            return new date(new DateValue(v1.Value));
                        }
                        return null;
                    }

                    if (value is string)
                    {
                        DateValue v = DateValue.MinValue;
                        if (DateValue.TryParse(value as string, out v))
                        {
                            return new date(v);
                        }
                        return null;
                    }

                    if (value is Guid)
                    {
                        return ToDate(((Guid)value).ToByteArray());
                    }

                    if (value is DateTime)
                    {
                        return new date((DateTime)value);
                    }

                    if (value is DateTimeOffset)
                    {
                        var v4 = (DateTimeOffset)value;
                        return new date(v4.Year, v4.Month, v4.Day);
                    }

                    if (value is TimeSpan)
                    {
                        return new date(new DateTime(((TimeSpan)value).Ticks));
                    }

                    if (value is bool)
                    {
                        return ((bool)value) ? DateTime.Now : DateTime.MinValue;
                    }

                    if (value is byte)
                    {
                        return new DateTime((long)((int)(byte)value));
                    }

                    if (value is sbyte)
                    {
                        return new DateTime((long)((int)(sbyte)value));
                    }

                    if (value is short)
                    {
                        return new DateTime((long)((int)(short)value));
                    }

                    if (value is ushort)
                    {
                        return new DateTime((long)((int)(ushort)value));
                    }

                    if (value is int)
                    {
                        return new DateTime((long)((int)value));
                    }

                    if (value is uint)
                    {
                        return new DateTime((long)((uint)value));
                    }

                    if (value is long)
                    {
                        return new DateTime((long)(value));
                    }

                    if (value is ulong)
                    {
                        return new DateTime((long)((ulong)value));
                    }

                    if (value is decimal)
                    {
                        return new DateTime((long)((decimal)value));
                    }

                    if (value is float)
                    {
                        return new DateTime((long)((float)value));
                    }

                    if (value is double)
                    {
                        return new DateTime((long)((double)value));
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region ToDateTime

        internal static @datetime? ToDateTime(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        var v1 = ToInt64(value as byte[]);
                        if (v1.HasValue)
                        {
                            return new DateTime(v1.Value);
                        }
                        return null;
                    }

                    if (value is string)
                    {
                        DateTime v = DateTime.MinValue;
                        if (DateTime.TryParse(value as string, out v))
                        {
                            return v;
                        }
                        return null;
                    }

                    if (value is Guid)
                    {
                        return ToDateTime(((Guid)value).ToByteArray());
                    }

                    if (value is DateTime)
                    {
                        return (DateTime)value;
                    }

                    if (value is DateTimeOffset)
                    {
                        return ((DateTimeOffset)value).UtcDateTime;
                    }

                    if (value is TimeSpan)
                    {
                        return new DateTime(((TimeSpan)value).Ticks);
                    }

                    if (value is bool)
                    {
                        return ((bool)value) ? DateTime.Now : DateTime.MinValue;
                    }

                    if (value is byte)
                    {
                        return new DateTime((long)((int)(byte)value));
                    }

                    if (value is sbyte)
                    {
                        return new DateTime((long)((int)(sbyte)value));
                    }

                    if (value is short)
                    {
                        return new DateTime((long)((int)(short)value));
                    }

                    if (value is ushort)
                    {
                        return new DateTime((long)((int)(ushort)value));
                    }

                    if (value is int)
                    {
                        return new DateTime((long)((int)value));
                    }

                    if (value is uint)
                    {
                        return new DateTime((long)((uint)value));
                    }

                    if (value is long)
                    {
                        return new DateTime((long)(value));
                    }

                    if (value is ulong)
                    {
                        return new DateTime((long)((ulong)value));
                    }

                    if (value is decimal)
                    {
                        return new DateTime((long)((decimal)value));
                    }

                    if (value is float)
                    {
                        return new DateTime((long)((float)value));
                    }

                    if (value is double)
                    {
                        return new DateTime((long)((double)value));
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region ToTime

        internal static @time? ToTime(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        return BitConverter.ToInt32(BinaryHelper.PadRight(value as byte[], 4), 0);
                    }

                    if (value is string)
                    {
                        return @time.Parse(value as string);
                    }

                    if (value is Guid)
                    {
                        return BitConverter.ToInt32(((Guid)value).ToByteArray(), 0);
                    }

                    if (value is DateTime)
                    {
                        return (int)((DateTime)value).Ticks;
                    }

                    if (value is DateTimeOffset)
                    {
                        return (int)((DateTimeOffset)value).Ticks;
                    }

                    if (value is TimeSpan)
                    {
                        return (time)(TimeSpan)value;
                    }

                    if (value is bool)
                    {
                        return ((bool)value) ? 1 : 0;
                    }

                    if (value is byte)
                    {
                        return (byte)value;
                    }

                    if (value is sbyte)
                    {
                        return (sbyte)value;
                    }

                    if (value is short)
                    {
                        return (short)value;
                    }

                    if (value is ushort)
                    {
                        return (ushort)value;
                    }

                    if (value is int)
                    {
                        return (int)value;
                    }

                    if (value is uint)
                    {
                        return (int)(uint)value;
                    }

                    if (value is long)
                    {
                        return (int)(long)value;
                    }

                    if (value is ulong)
                    {
                        return (int)(ulong)value;
                    }

                    if (value is decimal)
                    {
                        return (int)(decimal)value;
                    }

                    if (value is float)
                    {
                        return (int)(float)value;
                    }

                    if (value is double)
                    {
                        return (int)(double)value;
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region ToInterval

        internal static @interval? ToInterval(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        return BitConverter.ToInt64(BinaryHelper.PadRight(value as byte[], 8), 0);
                    }

                    if (value is string)
                    {
                        return @interval.Parse(value as string);
                    }

                    if (value is Guid)
                    {
                        return BitConverter.ToInt64(((Guid)value).ToByteArray(), 0);
                    }

                    if (value is DateTime)
                    {
                        return ((DateTime)value).Ticks;
                    }

                    if (value is DateTimeOffset)
                    {
                        return ((DateTimeOffset)value).Ticks;
                    }

                    if (value is TimeSpan)
                    {
                        return ((TimeSpan)value).Ticks;
                    }

                    if (value is bool)
                    {
                        return ((bool)value) ? 1L : 0L;
                    }

                    if (value is byte)
                    {
                        return (byte)value;
                    }

                    if (value is sbyte)
                    {
                        return (sbyte)value;
                    }

                    if (value is short)
                    {
                        return (short)value;
                    }

                    if (value is ushort)
                    {
                        return (ushort)value;
                    }

                    if (value is int)
                    {
                        return (int)value;
                    }

                    if (value is uint)
                    {
                        return (uint)value;
                    }

                    if (value is long)
                    {
                        return (long)value;
                    }

                    if (value is ulong)
                    {
                        return (long)(ulong)value;
                    }

                    if (value is decimal)
                    {
                        return (long)(decimal)value;
                    }

                    if (value is float)
                    {
                        return (long)(float)value;
                    }

                    if (value is double)
                    {
                        return (long)(double)value;
                    }
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region ToString

        internal static @string? ToString(object value)
        {
            try
            {
                unchecked
                {
                    if (value is byte[])
                    {
                        var v = value as byte[];
                        return v.Length == 0 ? ""  : System.Text.Encoding.UTF8.GetString(v);
                    }

                    if (value is string)
                    {
                        return value as string;
                    }

                    return value.ToString();
                }
            }
            catch
            {
            }

            return null;
        }

        #endregion

        #region Convert

        /// <summary>
        /// 将指定的值转换为目标 <see cref="IPrimitive"/> 类型的值。
        /// </summary>
        /// <typeparam name="T">目标类型。</typeparam>
        /// <param name="value">要转换的字符串值。</param>
        /// <returns>转换后的值，如果无法完成转换，则返回 null。</returns>
        public static T? To<T>(this object value) where T : struct, IPrimitive
        {
            return (T?)To(value, typeof(T));
        }

        /// <summary>
        /// 将指定的值转换为目标 <see cref="IPrimitive"/> 类型的值。
        /// </summary>
        /// <param name="value">要转换的字符串值。</param>
        /// <param name="type">要转换的目标类型。</param>
        /// <returns>转换后的值，如果无法完成转换，则返回 null。</returns>
        public static object To(this object value, Type type)
        {
            value = value == DBNull.Value ? null : value;

            if (type == typeof(@bool) || type == typeof(@bool?))
            {
                return ToBoolean(value);
            }

            if (type == typeof(@uuid) || type == typeof(@uuid?))
            {
                return ToUuid(value);
            }

            if (type == typeof(@string) || type == typeof(@string?))
            {
                return ToString(value);
            }

            if (type == typeof(@binary) || type == typeof(@binary?))
            {
                return ToBinary(value);
            }

            if (type == typeof(@int8) || type == typeof(@int8?))
            {
                return ToInt8(value);
            }
            
            if (type == typeof(@int16) || type == typeof(@int16?))
            {
                return ToInt16(value);
            }
            
            if (type == typeof(@int32) || type == typeof(@int32?))
            {
                return ToInt32(value);
            }
            
            if (type == typeof(@int64) || type == typeof(@int64?))
            {
                return ToInt64(value);
            }
            
            if (type == typeof(@decimal) || type == typeof(@decimal?))
            {
                return ToDecimal(value);
            }

            if (type == typeof(@float32) || type == typeof(@float32?))
            {
                return ToSingle(value);
            }

            if (type == typeof(@float64) || type == typeof(@float64?))
            {
                return ToDouble(value);
            }

            if (type == typeof(@datetime) || type == typeof(@datetime?))
            {
                return ToDateTime(value);
            }

            if (type == typeof(@date) || type == typeof(@date?))
            {
                return ToDate(value);
            }
            
            if (type == typeof(@time) || type == typeof(@time?))
            {
                return ToTime(value);
            }

            if (type == typeof(@interval) || type == typeof(@interval?))
            {
                return ToInterval(value);
            }

            return Convert.ChangeType(value, type);
        }

        #endregion

        #region String & Binary Helpers

        /// <summary>
        /// 指示指定的二进制串是否是空引用或空串。
        /// </summary>
        /// <param name="s">二进制串。</param>
        /// <returns>如果二进制串是空引用或者空串，返回 true，否则返回 false。</returns>
        public static bool IsNullOrEmpty(this @binary? s)
        {
            return !s.HasValue || s.Value.IsEmpty;
        }

        /// <summary>
        /// 指示指定的字符串是否是空引用或空字符串。
        /// </summary>
        /// <param name="s">字符串。</param>
        /// <returns>如果字符串是空引用或者空字符串，返回 true，否则返回 false。</returns>
        public static bool IsNullOrEmpty(this @string? s)
        {
            return !s.HasValue || s.Value.IsEmpty;
        }

        /// <summary>
        /// 比较两个字符串是否相等。
        /// </summary>
        /// <param name="x">第一个字符串。</param>
        /// <param name="y">第二个字符串。</param>
        /// <param name="comparison">比较方法。</param>
        /// <returns>如果两个字符串相等，则返回 true，否则返回 false。</returns>
        public static bool Equals(this @string? x, @string? y, StringComparison comparison)
        {
            if (x.HasValue)
            {
                if (y.HasValue)
                {
                    return String.Equals(x.Value, y.Value, comparison);
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return !y.HasValue;
            }
        }

        /// <summary>
        /// 返回指定字符串的小写形式。
        /// </summary>
        /// <param name="s">一个字符串。</param>
        /// <returns>字符串的小写形式。</returns>
        public static @string? ToLower(this @string? s)
        {
            if (s.HasValue)
            {
                return (@string)(((string)s.Value).ToLower());
            }

            return null;
        }

        /// <summary>
        /// 返回指定字符串的大写形式。
        /// </summary>
        /// <param name="s">一个字符串。</param>
        /// <returns>字符串的大写形式。</returns>
        public static @string? ToUpper(this @string? s)
        {
            if (s.HasValue)
            {
                return (@string)(((string)s.Value).ToUpper());
            }

            return null;
        }

        #endregion

        #region Nullable Primitive Write

        /// <summary>
        /// 将指定的值作为 JSON 字符串写入指定的文本流。
        /// </summary>
        /// <typeparam name="T">目标值的类型。</typeparam>
        /// <param name="value">要写入到 JSON 字符串的值。</param>
        /// <param name="writer">目标文本流。</param>
        /// <exception cref="global::System.ArgumentNullException">writer 是 null。</exception>
        public static void Write<T>(this T? value, System.IO.TextWriter writer) where T : struct, IPrimitive
        {
            if (writer == null)
            {
                throw new global::System.ArgumentNullException("writer");
            }

            if (!value.HasValue)
            {
                writer.Write("null");
            }
            else
            {
                value.Value.Write(writer);
            }
        }

        #endregion
    }
}
